package cn.jsj.onclock.service.impl;

import cn.jsj.onclock.dao.GroupDao;
import cn.jsj.onclock.dao.UserDao;
import cn.jsj.onclock.dao.UserJoinRequestDao;
import cn.jsj.onclock.exception.CustomException;
import cn.jsj.onclock.pojo.GroupEnt;
import cn.jsj.onclock.pojo.UserEnt;
import cn.jsj.onclock.pojo.UserGroupInfo;
import cn.jsj.onclock.pojo.identity.GroupIdentityEnum;
import cn.jsj.onclock.pojo.identity.GroupJoinAuthEnum;
import cn.jsj.onclock.pojo.identity.UserIdentityEnum;
import cn.jsj.onclock.service.GroupService;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

/**
 * @author 卢斌
 */
@Service
public class GroupServiceImpl implements GroupService {


    private final GroupDao groupDao;

    private final UserDao userDao;

    private final UserJoinRequestDao userJoinRequestDao;

    @Autowired
    public GroupServiceImpl(GroupDao groupDao, UserDao userDao, UserJoinRequestDao userJoinRequestDao) {
        this.groupDao = groupDao;
        this.userDao = userDao;
        this.userJoinRequestDao = userJoinRequestDao;
    }

    /**
     * 创建一个群组
     *
     * @param groupName     群名称
     * @param creatorId     创建者Id
     * @param userIdentity  用户角色
     * @return 新群Id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long creatGroup(String groupName, Long creatorId, UserIdentityEnum userIdentity) {
        // 校验用户身份信息，判断是否具有创建群组的权限
        if (! UserIdentityEnum.hasCreateGroupPower(userIdentity)) {
            throw new CustomException("用户暂无创建群组的权限");
        }

        // 尝试新增一个仅仅包含最基本信息的群组记录
        GroupEnt insertBody = new GroupEnt();
        insertBody.setGroupName(groupName);
        insertBody.setLeaderId(creatorId);
        groupDao.insertOneGroup(insertBody);

        // 群组创建完成后，创建者默认是群组成员。把创建群组的用户加入到新群组中
        groupDao.insertUserToGroup(insertBody.getId(), creatorId, GroupIdentityEnum.MASTER);
        return insertBody.getId();
    }



    /**
     * 获取用户加入的群组列表，分页显示
     *
     * @param userId    用户Id
     * @param pageNum   页码
     * @param pageSize  页容量
     * @return  用户加入的群组
     */
    @Override
    public List<UserGroupInfo> listUserGroupInformationAboutUser(Long userId, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return groupDao.listUserGroupInfoAboutUser(userId);
    }

    /**
     * 获取某一群组内的成员信息
     *
     * @param userId    用户Id
     * @param groupId   群组Id
     * @param pageNum   页码号
     * @param pageSize  页容量
     * @return  该群内的所有成员信息
     */
    @Override
    public List<UserGroupInfo> listUserInfoInGroup(Long userId , Long groupId, Integer pageNum, Integer pageSize) {
        // 检查用户是否在该群组中
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfo(groupId, userId);
        if (userGroupInfo == null) {
            throw new CustomException("您不在该群组内, 无法获取成员信息");
        }
        PageHelper.startPage(pageNum, pageSize);
        return groupDao.listUserJoinGroupInfoWithUser(groupId);
    }

    /**
     * 获取某一群组内的成员信息
     *
     * @param userId  用户Id
     * @param groupId 群组Id
     * @return 该群内的所有成员信息
     */
    @Override
    public List<UserGroupInfo> listUserInfoInGroupWithoutPage(Long userId, Long groupId) {
        // 检查用户是否在该群组中
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfo(groupId, userId);
        if (userGroupInfo == null) {
            throw new CustomException("您不在该群组内, 无法获取成员信息");
        }
        return groupDao.listUserJoinGroupInfoWithUser(groupId);
    }

    /**
     * 修改群组名称
     *
     * @param userId  用户Id
     * @param groupId 群组Id
     * @param newName 群组新名称
     * @return 新名称
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String updateGroupName(Long userId, Long groupId, String newName) {
        // 检查用户是否在该群组中
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfoWithGroupEnt(groupId, userId);
        if (userGroupInfo == null) {
            throw new CustomException("用户不在该群组中");
        }

        // 检查用户身份是否可以修改群组名称
        if (GroupIdentityEnum.hasPowerOfUpdateGroupName(userGroupInfo.getRole())) {
            if (newName.equals(userGroupInfo.getGroupEnt().getGroupName())) {
                throw new CustomException("名称未发生变化，不需要修改");
            }
            groupDao.updateGroupName(groupId, newName);
            return newName;
        } else {
            throw new CustomException("您没有修改群组名称的权限");
        }
    }

    /**
     * 解散一个群组
     *
     * @param userId  用户Id
     * @param groupId 群组Id
     * @return 数据库影响条数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long deleteOneGroup(Long userId, Long groupId) {
        // 检查用户是否在该群组中
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfo(groupId, userId);
        if (userGroupInfo == null) {
            throw new CustomException("用户不在该群组中");
        }
        if (GroupIdentityEnum.hasPowerOfDeleteGroup(userGroupInfo.getRole())) {

            // 删除群组大纲信息
            Integer deleteNumber = groupDao.deleteGroup(groupId);
            if (deleteNumber == 0) {
                throw new CustomException("该群已被删除");
            }

            // 删除群组内成员信息
            groupDao.deleteJoinGroupInfo(groupId);

            // 删除群组相关的加群申请记录
            userJoinRequestDao.deleteUserJoinRequests(groupId);
            return groupId;
        }
        throw new CustomException("您没有解散该群组的权限");
    }

    /**
     * 模糊查询群组列表
     *
     * @param groupNamePrefix   群名称前缀
     * @param pageNum           页码号
     * @param pageSize          页容量
     * @return 符合前缀规则的群列表
     */
    @Override
    public List<GroupEnt> findNameGroup(String groupNamePrefix, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return groupDao.listLikeName(groupNamePrefix);
    }

    /**
     * 获取用户在某群组中的成员信息（一般用于检查用户是否在该群组中）
     *
     * @param userId  用户Id
     * @param groupId 群组Id
     * @return 用户在该群中的成员信息
     */
    @Override
    public UserGroupInfo getUserGroupInfo(Long userId, Long groupId) {
        return groupDao.getUserJoinGroupInfo(groupId, userId);
    }

    /**
     * 用户修改群审批方式
     *
     * @param userId        操作用户Id
     * @param groupId       群组Id
     * @param authEnum      默认审批方式
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateGroupAuthWay(Long userId, Long groupId, GroupJoinAuthEnum authEnum) {
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfo(groupId, userId);
        if (userGroupInfo == null) {
            throw new CustomException("用户不在该群组中，无法修改群组信息");
        }

        if (GroupIdentityEnum.hasPowerOfUpdateAuthWay(userGroupInfo.getRole())) {
            Integer influenceNumber = groupDao.updateGroupRequestAuthWay(authEnum, groupId);
            if (influenceNumber == 0) {
                throw new CustomException("您没有修改成功");
            }
        } else {
            throw new CustomException("您没有修改该信息的权限");
        }
    }

    /**
     * 查询符合前缀规则的用户已经加入的群组
     *
     * @param userId   用户Id
     * @param prefix   模糊查询前缀
     * @param pageNum  页码号
     * @param pageSize 页容量
     * @return 符合前缀规则的用户已经加入的群组
     */
    @Override
    public List<UserGroupInfo> listGroupLikePrefixNameAboutUser(Long userId, String prefix, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return groupDao.listUserGroupInfoLikeGroupName(userId, prefix);
    }

    /**
     * 查询群组中的某位用户的个人信息
     *
     * @param userId   用户Id
     * @param friendId 群友Id
     * @param groupId  群组Id
     * @return 群友个人信息
     */
    @Override
    public UserEnt getOneGroupFriendInfo(Long userId, Long friendId, Long groupId) {
        Boolean selfInGroup = groupDao.userIsInGroup(userId, groupId);
        if (! selfInGroup) {
            throw new CustomException("您不在该群组中");
        }
        Boolean targetInGroup = groupDao.userIsInGroup(friendId, groupId);
        if (! targetInGroup) {
            throw new CustomException("对方不在该群组中");
        }
        return userDao.getUserEntityById(friendId);
    }


}
